import re
import json
from itertools import product
import time
from datetime import datetime
from datetime import datetime, timedelta, timezone
from dateutil.relativedelta import relativedelta

from src.chat_utils import create_chat, create_chat_with_options


east8_zone = timezone(timedelta(hours=8))


# prompt 相关
def remove_parentheses(query):
    return query.replace('{', '{{').replace('}', '}}')


# extraction 提取数据
def extract_json_from_markdown(markdown_text):
    # 使用正则表达式匹配代码块中的JSON内容
    pattern = r'```json\s*([\s\S]*?)\s*```'
    matches = re.findall(pattern, markdown_text)

    # 返回所有匹配到的JSON内容
    return matches[0]


# milvus 向量相关
def search_question(question):
    question = remove_parentheses(question)


# cola时间解析
def extract_time_components(time_str):
    pattern = r'(\d+)([YmdHMSQW])'
    matches = re.findall(pattern, time_str)
    result = {}
    for number, letter in matches:
        result[letter] = int(number)
    return result


def parse_cola_time(cola_time):
    if "NONETIME" in cola_time:
        return None

    # res = extract_json_from_markdown(cola_time)
    # columns = json.loads(res)
    # target_time = columns["time"]
    target_time = cola_time
    old_time_lst, target_time_lst = [], []
    for key, val in target_time.items():
        old_time_lst.append(key)
        target_time_lst.append(val)
    # target_time_lst = target_time.split(",")

    print(target_time_lst)
    res_time = []

    for ftime in target_time_lst:
        if "~" in ftime:
            time_during_lst = ftime.split("~")

            begin_time, _, _ = get_cola_base_time_include_past_time_and_most(time_during_lst[0])
            _, end_time, _ = get_cola_base_time_include_past_time_and_most(time_during_lst[1])
        else:
            begin_time, end_time, _ = get_cola_base_time_include_past_time_and_most(ftime)
        res_time.append([begin_time, end_time])

    print(res_time)
    return old_time_lst, res_time


def get_cola_base_time_include_past_time_and_most(target_time):
    if "*" in target_time:
        base_time, mark_time = target_time.split("*")
        start_time, end_time, during_mark = get_base_time_include_past_time(base_time)
        extra_time = extract_time_components(mark_time)
        if mark_time.startswith("+"):
            start_time = end_time
            if "m" in extra_time:
                start_time -= relativedelta(months=extra_time.get("m", 0))
            elif "Q" in extra_time:
                start_time -= relativedelta(months=(extra_time.get("Q", 0) * 3))
            if "d" in extra_time:
                start_time -= relativedelta(days=extra_time.get("d", 0))
            elif "W" in extra_time:
                start_time -= relativedelta(months=(extra_time.get("W", 0) * 7))
            start_time -= relativedelta(hours=(extra_time.get("H", 0)))
            start_time -= relativedelta(minutes=(extra_time.get("M", 0)))
            start_time -= relativedelta(seconds=(extra_time.get("S", 0)))
        else:
            end_time = start_time
            if "m" in extra_time:
                end_time += relativedelta(months=extra_time.get("m", 0))
            elif "Q" in extra_time:
                end_time += relativedelta(months=(extra_time.get("Q", 0) * 3))
            if "d" in extra_time:
                end_time += relativedelta(days=extra_time.get("d", 0))
            elif "W" in extra_time:
                end_time += relativedelta(days=(extra_time.get("W", 0) * 7))
            end_time += relativedelta(hours=(extra_time.get("H", 0)))
            end_time += relativedelta(minutes=(extra_time.get("M", 0)))
            end_time += relativedelta(seconds=(extra_time.get("S", 0)))

        during_mark = mark_time

    else:
        start_time, end_time, during_mark = get_base_time_include_past_time(target_time)

    return start_time, end_time, during_mark


def get_base_time_include_past_time(target_time):
    if target_time == "now":
        now = datetime.now(east8_zone)
        begin_start = datetime(year=now.year, month=now.month, day=now.day)
        return begin_start, now, "now"
    elif target_time.startswith("--"):
        res_time = get_cola_previous_time(target_time)
    elif target_time.startswith("-"):
        res_time = get_cola_past_time(target_time)
    else:
        res_time = get_cola_base_time(target_time)

    return res_time


def get_cola_base_time(target_time):
    now = datetime.now(east8_zone)
    during_mark = False

    target_time_dict = extract_time_components(target_time)
    res_time_dict = {}
    if target_time_dict.get("Y"):
        res_time_dict["Y"] = target_time_dict["Y"]
        during_mark = "Y"
    else:
        res_time_dict["Y"] = now.year

    if target_time_dict.get("m"):
        res_time_dict["m"] = target_time_dict["m"]
        during_mark = "m"
    else:
        if target_time_dict.get("Q"):
            res_time_dict["m"] = target_time_dict["Q"] * 3 - 2
            during_mark = "Q"
        else:
            if not during_mark:  # 是否补 比如 2024Y 已经确认时间不补 3m24d 未确认时间补
                res_time_dict["m"] = now.month
            else:
                res_time_dict["m"] = 1

    if target_time_dict.get("d"):
        res_time_dict["d"] = target_time_dict["d"]
        during_mark = "d"
    else:
        if target_time_dict.get("W"):
            res_time_dict["d"] = target_time_dict["W"] * 7 - 6
            during_mark = "W"
        else:
            if not during_mark:
                res_time_dict["d"] = now.day
            else:
                res_time_dict["d"] = 1

    if target_time_dict.get("H"):
        res_time_dict["H"] = target_time_dict["H"]
        during_mark = "H"
    else:
        res_time_dict["H"] = 0

    if target_time_dict.get("M"):
        res_time_dict["M"] = target_time_dict["M"]
        during_mark = "M"
    else:
        res_time_dict["M"] = 0

    if target_time_dict.get("S"):
        res_time_dict["S"] = target_time_dict["S"]
        during_mark = "S"
    else:
        res_time_dict["S"] = 0

    res_start_time = datetime(year=res_time_dict['Y'], month=1, day=1)
    res_start_time += relativedelta(months=(res_time_dict['m'] - 1))
    res_start_time += relativedelta(days=(res_time_dict['d'] - 1))
    res_start_time += relativedelta(hours=res_time_dict['H'])
    res_start_time += relativedelta(minutes=res_time_dict['M'])
    res_start_time += relativedelta(seconds=res_time_dict['S'])

    if during_mark == "Y":
        res_end_time = res_start_time + relativedelta(years=1)
    elif during_mark == "m":
        res_end_time = res_start_time + relativedelta(months=1)
    elif during_mark == "Q":
        res_end_time = res_start_time + relativedelta(months=3)
    elif during_mark == "d":
        res_end_time = res_start_time + relativedelta(days=1)
    elif during_mark == "W":
        res_end_time = res_start_time + relativedelta(days=7)
    elif during_mark == "H":
        res_end_time = res_start_time + relativedelta(hours=1)
    elif during_mark == "M":
        res_end_time = res_start_time + relativedelta(minutes=1)
    elif during_mark == "S":
        res_end_time = res_start_time + relativedelta(seconds=1)
    else:
        res_end_time = res_start_time + relativedelta(days=1)

    return res_start_time, res_end_time, during_mark


def get_cola_previous_time(target_time):  # --
    now = datetime.now(east8_zone)
    during_mark = False

    target_time_dict = extract_time_components(target_time)

    res_time_dict = {}
    res_next_time_dict = {}
    res_minus = {}
    if "Y" in target_time_dict:
        res_minus["Y"] = res_minus.get("Y", 0) - target_time_dict["Y"]
        during_mark = "Y"

    if "m" in target_time_dict:
        res_minus["m"] = res_minus.get("m", 0) - target_time_dict["m"]
        during_mark = "m"
    elif "Q" in target_time_dict:
        res_minus["m"] = res_minus.get("m", 0) - ((now.month - 1) % 3) - target_time_dict["Q"] * 3
        during_mark = "Q"

    if "d" in target_time_dict:
        res_minus["d"] = res_minus.get("d", 0) - target_time_dict["d"]
        during_mark = "d"
    elif "W" in target_time_dict:
        res_minus["d"] = res_minus.get("d", 0) - target_time_dict[
            "W"] * 7 - now.weekday()  # now.weekday() 默认从0开始 刚好
        during_mark = "W"

    if "H" in target_time_dict:
        res_minus["H"] = res_minus.get("H", 0) - target_time_dict["H"]
        during_mark = "H"

    if "M" in target_time_dict:
        res_minus["M"] = res_minus.get("M", 0) - target_time_dict["M"]
        during_mark = "M"

    if "S" in target_time_dict:
        res_minus["S"] = res_minus.get("S", 0) - target_time_dict["S"]
        during_mark = "S"

    res_time = now
    res_time += relativedelta(years=res_minus.get("Y", 0))
    res_time += relativedelta(months=res_minus.get("m", 0))
    res_time += relativedelta(days=res_minus.get("d", 0))
    res_time += relativedelta(hours=res_minus.get("H", 0))
    res_time += relativedelta(minutes=res_minus.get("M", 0))
    res_time += relativedelta(seconds=res_minus.get("S", 0))
    # res_time += relativedelta(weeks=res_minus.get("W", 0))
    # res_time += relativedelta(days=res_minus.get("H", 0))

    if during_mark in "Y":
        res_start_time = datetime(year=res_time.year, month=1, day=1)
        res_end_time = res_start_time + relativedelta(years=1)


    elif during_mark == "m" or during_mark == "Q":
        res_start_time = datetime(year=res_time.year, month=res_time.month, day=1)

        if during_mark == "Q":
            res_end_time = res_start_time + relativedelta(months=3)
        else:
            res_end_time = res_start_time + relativedelta(months=1)


    elif during_mark == "d" or during_mark == "W":
        res_start_time = datetime(year=res_time.year, month=res_time.month, day=res_time.day)

        if during_mark == "W":
            res_end_time = res_start_time + relativedelta(days=7)
        else:
            res_end_time = res_start_time + relativedelta(days=1)


    elif during_mark == "H":
        res_start_time = datetime(year=res_time.year, month=res_time.month, day=res_time.day, hour=res_time.hour)
        res_end_time = res_start_time + relativedelta(hours=1)


    elif during_mark == "M":
        res_start_time = datetime(year=res_time.year, month=res_time.month, day=res_time.day, hour=res_time.hour,
                                  minute=res_time.minute)
        res_end_time = res_start_time + relativedelta(minutes=1)

    elif during_mark == "S":
        res_start_time = datetime(year=res_time.year, month=res_time.month, day=res_time.day, hour=res_time.hour,
                                  minute=res_time.minute, second=res_time.second)
        res_end_time = res_start_time + relativedelta(seconds=1)

    return res_start_time, res_end_time, during_mark


def get_cola_past_time(target_time):
    now = datetime.now(east8_zone)

    target_time_dict = extract_time_components(target_time)

    res_time = now
    res_time -= relativedelta(years=target_time_dict.get("Y", 0))
    res_time -= relativedelta(months=target_time_dict.get("m", 0))
    res_time -= relativedelta(days=target_time_dict.get("d", 0))
    res_time -= relativedelta(hours=target_time_dict.get("H", 0))
    res_time -= relativedelta(minutes=target_time_dict.get("M", 0))
    res_time -= relativedelta(seconds=target_time_dict.get("S", 0))
    res_time -= relativedelta(days=target_time_dict.get("W", 0) * 7)
    res_time -= relativedelta(months=target_time_dict.get("Q", 0)*3)

    return res_time, now, "now"


# 时间字符串转时间戳
def data_str2timestamp(date_str):   # 入参东八区时间字符串
    # 将字符串转换为 datetime 对象，并设置为 UTC 时间
    # TODO 确定这里用utc时间还是要转+8区  .replace(tzinfo=timezone.utc)
    if len(date_str) == 10:
        date_obj = datetime.strptime(date_str, "%Y-%m-%d").replace(tzinfo=east8_zone)
    else:
        date_obj = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S").replace(tzinfo=east8_zone)

    # 将 datetime 对象转换为时间戳
    timestamp = date_obj.timestamp() * 1000
    return timestamp


# 时间戳转时间字符串
def timestamp2data_str(timestamp):
    return time.strftime("%Y-%m-%d", time.localtime(timestamp))


# 排序
def sort_by_first_element(data):
    # 使用sorted函数，key参数指定为每个子数组的第一个元素
    sorted_data = sorted(data, key=lambda x: x[0])
    return sorted_data


# 分解
def expand_dict(input_dict):
    # 使用字典推导式删除值为False的项
    input_dict = {k: v for k, v in input_dict.items() if v}

    # 首先，我们确定哪些key需要展开（即那些value是列表的key）
    keys_to_expand = [key for key, value in input_dict.items() if isinstance(value, list)]

    # 如果没有需要展开的key，直接返回原字典的列表形式
    if not keys_to_expand:
        return [input_dict.copy()]

    # 为每个需要展开的key创建一个包含其所有可能值的列表
    values_to_expand = [input_dict[key] for key in keys_to_expand]

    # 使用itertools.product计算所有可能的组合
    expanded_combinations = product(*values_to_expand)

    # 创建结果列表
    result = []
    for combination in expanded_combinations:
        new_dict = input_dict.copy()
        for key, value in zip(keys_to_expand, combination):
            new_dict[key] = value
        result.append(new_dict)

    return result


# 验证 选项值或字段是否存在 存在不留 不存在筛除 如果没有值NONE 全查
def filter_choose(values, values_mapping):
    if isinstance(values, str) and values in values_mapping:
        return [values_mapping[values]]
    elif isinstance(values, list):
        target_correct_columns = []
        for v in values:
            if v in values_mapping:
                target_correct_columns.append(values_mapping[v])
        if len(target_correct_columns) > 0:
            return target_correct_columns
    return None

# 时间戳转时间字符串
def timestamp2timestr(timestamp):
    utc_time = datetime.fromtimestamp(timestamp)
    # 格式化为字符串
    formatted_time = utc_time.strftime("%Y-%m-%d %H:%M:%S")
    return formatted_time


def decimal_to_chinese(text):
    # 数字到中文的映射
    digit_map = {
        '0': '零',
        '1': '一',
        '2': '二',
        '3': '三',
        '4': '四',
        '5': '五',
        '6': '六',
        '7': '七',
        '8': '八',
        '9': '九',
        '.': '点'
    }

    # 单位映射
    unit_map = ['', '十', '百', '千']

    def integer_to_chinese(num_str):
        """将整数部分转为中文"""
        result = []
        zero_flag = False  # 标记是否有连续的零

        # 处理开头的零
        num_str = num_str.lstrip('0')
        if not num_str:  # 如果全是零
            return digit_map['0']

        for i, digit in enumerate(reversed(num_str)):
            # 从低位到高位处理，单位是 unit_map[i % 4]
            unit = ''
            if i > 0 and i % 4 == 0:
                unit = '万' if i < 8 else '亿'
            elif i > 0:
                unit = unit_map[i % 4]

            if digit == '0':
                zero_flag = True
                # 在万/亿单位时需要添加单位
                if unit in ('万', '亿'):
                    if result and result[-1] == digit_map['0']:
                        result.pop()
                    result.append(unit)
                    zero_flag = False
                continue

            if zero_flag:
                result.append(digit_map['0'])
                zero_flag = False

            result.append(digit_map[digit] + unit)

        # 反转回高位到低位
        result = reversed(result)

        # 处理特殊情况：一十开头的简化为十
        result = ''.join(result)
        if result.startswith('一十'):
            result = result[1:]

        return result

    def replace_match(match):
        """替换匹配到的小数"""
        number = match.group()
        integer_part, _, decimal_part = number.partition('.')

        # 转换整数部分
        chinese_integer = integer_to_chinese(integer_part) if integer_part else digit_map['0']

        # 转换小数部分（直接一一对应）
        chinese_decimal = ''.join(digit_map[char] for char in decimal_part)

        return chinese_integer + '点' + chinese_decimal

    # 使用正则表达式查找所有小数
    return re.sub(r'\d+\.\d+', replace_match, text)


def percent_to_chinese(text):
    """
    将字符串中的所有百分数（如23%）转换为中文表示（如百分之23）
    """
    return re.sub(r'(\d+)%', r'百分之\1', text)
